package com.qyer.commons.service.server;

import com.qyer.commons.mc.MutableCache;
import com.qyer.commons.mc.reloader.DirectInvocationReloader;
import com.qyer.commons.mc.reloader.Reloader;
import com.qyer.commons.place.City;
import com.qyer.commons.place.Country;
import com.qyer.commons.place.Province;
import com.qyer.commons.service.conf.CommonsConf;
import com.qyer.commons.service.conf.CommonsMetaInfo;
import com.qyer.commons.service.db.DMDBResourceManager;
import com.qyer.commons.service.db.QyerDBResourceManager;
import com.qyer.commons.service.health.PlaceHealthCheck;
import com.qyer.commons.service.model.PlaceDict;
import com.qyer.commons.service.resources.PlaceResource;
import com.qyer.commons.service.resources.RootResource;
import com.qyer.commons.service.service.PlaceService;
import io.dropwizard.Application;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.servlets.CrossOriginFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.DispatcherType;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;

/**
 * User: Z J Wu Date: 2016/02/18 Time: 14:15 Package: com.qyer.words.app.server
 */
public class PlaceServer extends Application<CommonsConf> {

  private static final Logger LOGGER = LoggerFactory.getLogger(PlaceServer.class);

  @Override
  public void initialize(Bootstrap<CommonsConf> bootstrap) {
    super.initialize(bootstrap);
  }

  @Override
  public void run(CommonsConf ccc, Environment environment) throws Exception {
    String serviceName = ccc.getServerName(), namespace = ccc.getNamespace();
    if (StringUtils.isBlank(serviceName) || StringUtils.isBlank(namespace)) {
      throw new Exception("Service name or namespace is empty.");
    }
    LOGGER.info("Starting server({}.{}).", serviceName, namespace);
    CommonsMetaInfo.SERVICE_NAME = serviceName;
    CommonsMetaInfo.NAMESPACE = namespace;

    LOGGER.info("QYER-DB is standby. Ping: {}", QyerDBResourceManager.getInstance().heartbeat());
    LOGGER.info("DM-DB is standby. Ping: {}", DMDBResourceManager.getInstance().heartbeat());
    LOGGER.info("Init dictionary reloader.");
    int interval = ccc.getReloadIntervalQyerPlace();
    PlaceService placeService = PlaceService.getInstance();

    Reloader<PlaceDict<Integer, Country>> countryDictReloader = new DirectInvocationReloader<>(
      "buildCountryDict", placeService);
    MutableCache<PlaceDict<Integer, Country>> countryDictMC = new MutableCache<>(
      "CONTINENT-COUNTRY-DICT", "字典工具(大洲->国家列表)", interval, countryDictReloader);

    Reloader<PlaceDict<Integer, City>> cityDictReloader = new DirectInvocationReloader<>(
      "buildCityDict", placeService);
    MutableCache<PlaceDict<Integer, City>> cityDictMC = new MutableCache<>("COUNTRY-CITY-DICT",
                                                                           "字典工具(国家->城市列表)",
                                                                           interval,
                                                                           cityDictReloader);

    Reloader<PlaceDict<Integer, City>> chinaCityDictReloader = new DirectInvocationReloader<>(
      "buildChinaCityDict", placeService);
    MutableCache<PlaceDict<Integer, City>> chinaCityDictMC = new MutableCache<>(
      "CHINA-PROVINCE-CITY-DICT", "字典工具(中国省份->城市列表)", interval, chinaCityDictReloader);

    Reloader<Map<Integer, Country>> allCountryMapReloader = new DirectInvocationReloader<>(
      "buildCountryInfoMap", placeService);
    MutableCache<Map<Integer, Country>> allCountryMapMC = new MutableCache<>("COUNTRY-DICT",
                                                                             "字典工具(国家id->详情)",
                                                                             interval,
                                                                             allCountryMapReloader);

    Reloader<Map<Integer, City>> allCityMapReloader = new DirectInvocationReloader<>(
      "buildCityInfoMap", placeService);
    MutableCache<Map<Integer, City>> allCityMapMC = new MutableCache<>("CITY-DICT",
                                                                       "字典工具(城市id->详情)", interval,
                                                                       allCityMapReloader);

    Reloader<List<Province>> chinaProvinceListReloader = new DirectInvocationReloader<>(
      "loadAllChinaProvinces", placeService);
    MutableCache<List<Province>> chinaProvinceListMC = new MutableCache<>("CHINA-PROVINCE-LIST",
                                                                          "字典工具(中国省份列表)", interval,
                                                                          chinaProvinceListReloader);

    new Thread(countryDictMC, "Reloader." + countryDictMC.getName()).start();
    new Thread(cityDictMC, "Reloader." + cityDictMC.getName()).start();
    new Thread(chinaCityDictMC, "Reloader." + chinaCityDictMC.getName()).start();

    new Thread(allCountryMapMC, "Reloader." + allCountryMapMC.getName()).start();
    new Thread(allCityMapMC, "Reloader." + allCityMapMC.getName()).start();

    new Thread(chinaProvinceListMC, "Reloader." + chinaProvinceListMC.getName()).start();

    String[] arr = StringUtils.split(ccc.getTestContinentIdString(), ',');
    final int[] testContinentIds, testCountryIds;
    testContinentIds = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
      testContinentIds[i] = Integer.parseInt(arr[i]);
    }
    arr = StringUtils.split(ccc.getTestCountryIdString(), ',');
    testCountryIds = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
      testCountryIds[i] = Integer.parseInt(arr[i]);
    }

    final PlaceHealthCheck placeHealthCheck = new PlaceHealthCheck(countryDictMC, cityDictMC,
                                                                   testContinentIds,
                                                                   testCountryIds);
    environment.healthChecks().register("PlaceHealthCheck", placeHealthCheck);
    LOGGER
      .info("Place health check is registered. Test continent ids: {}. Test counties ids: " + "{}",
            Arrays.toString(testContinentIds), Arrays.toString(testCountryIds));
    final RootResource rr = new RootResource();
    final PlaceResource pr = new PlaceResource(countryDictMC, cityDictMC, chinaCityDictMC,
                                               allCountryMapMC, allCityMapMC, chinaProvinceListMC);
    environment.jersey().register(rr);
    environment.jersey().register(pr);
    // 解决跨域问题
    environment.servlets().addFilter("CrossOriginFilter", new CrossOriginFilter())
               .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
    LOGGER.info("Rest resource inited and registered.");
  }

  public static void main(String[] args) throws Exception {
    try {
      new PlaceServer().run(args);
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    }
  }
}
